package com.crx.springbootinit.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.crx.springbootinit.common.ErrorCode;
import com.crx.springbootinit.exception.BusinessException;
import com.crx.springbootinit.mapper.PostMapper;
import com.crx.springbootinit.mapper.UserMapper;
import com.crx.springbootinit.model.dto.comment.CommentPostIdPageDTO;
import com.crx.springbootinit.model.dto.map.Coordinate;
import com.crx.springbootinit.model.dto.map.CoordinateDTO;
import com.crx.springbootinit.model.dto.page.PageVO;
import com.crx.springbootinit.model.dto.post.PostDto;
import com.crx.springbootinit.model.dto.post.PostOtherPageDTO;
import com.crx.springbootinit.model.dto.post.PostPageDTO;
import com.crx.springbootinit.model.dto.post.PostUserPageDTO;
import com.crx.springbootinit.model.entity.*;
import com.crx.springbootinit.model.vo.comment.CommentsVO;
import com.crx.springbootinit.model.vo.post.PostHomeVO;
import com.crx.springbootinit.model.vo.post.PostListVO;
import com.crx.springbootinit.model.vo.post.PostPageVO;
import com.crx.springbootinit.model.vo.post.PostVO;
import com.crx.springbootinit.service.*;
import com.crx.springbootinit.utils.ThreadLocalUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * <p>
 * 帖子表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-10-21
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements IPostService {
    @Autowired
    private ICommentService commentService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ILoveService loveService;
    @Autowired
    private ICollectService collectService;
    @Autowired
    private IFollowService followService;
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    private final static String key = "VEPBZ-UJ4KQ-IAS5R-4U2CW-F4372-SBBAI";

    /**
     * 发帖子
     *
     * @param postDto 帖子信息
     */
    @Override
    public void addPost(PostDto postDto) {
        Post post = new Post();
        BeanUtils.copyProperties(postDto, post);
        //计算距离
        String url = "https://apis.map.qq.com/ws/direction/v1/walking/?from={from}&to={to}&key={key}";
        // 将 JSON 字符串解析为 JSONArray
        JSONArray locations = JSONArray.parseArray(post.getRoute());
        //距离
        BigDecimal totalDistance = BigDecimal.ZERO;
        //路线
        List<Map<String, BigDecimal>> allCoordinates = new ArrayList<>();
        for (int i = 0; i < locations.size() - 1; i++) { // 遍历到倒数第二个元素
            // 封装传递参数
            Map<String, String> map = new HashMap<>();

            JSONObject currentLocation = locations.getJSONObject(i);
            JSONObject nextLocation = locations.getJSONObject(i + 1);

            double currentLatitude = currentLocation.getDouble("latitude");
            double currentLongitude = currentLocation.getDouble("longitude");
            double nextLatitude = nextLocation.getDouble("latitude");
            double nextLongitude = nextLocation.getDouble("longitude");

            // 设置开始位置（当前位置坐标）
            map.put("from", currentLatitude + "," + currentLongitude);
            // 设置结束位置（下一个位置坐标）
            map.put("to", nextLatitude + "," + nextLongitude);
            // key
            map.put("key", key);
            try {
                JSONObject responseEntity = restTemplate.getForObject(url, JSONObject.class, map);
                int status = responseEntity.getIntValue("status");
                if (status != 0) {
                    throw new BusinessException(ErrorCode.FEIGN_FAIL);
                }

                // 处理响应数据逻辑...
                //获取返回路线信息
                JSONObject route =
                        responseEntity.getJSONObject("result").getJSONArray("routes").getJSONObject(0);
                BigDecimal distance = route.getBigDecimal("distance").setScale(2, RoundingMode.HALF_UP);
                totalDistance = totalDistance.add(distance);

                // 解压 polyline 坐标
                JSONArray polyline = route.getJSONArray("polyline");
                List<BigDecimal> coors = new ArrayList<>();
                for (int k = 0; k < polyline.size(); k++) {
                    coors.add(polyline.getBigDecimal(k));
                }

                for (int k = 2; k < coors.size(); k++) {
                    coors.set(k, coors.get(k - 2).add(coors.get(k).divide(new BigDecimal(1000000))));
                }

                // 将解压后的坐标转换为 latitude 和 longitude 对象，并添加到全局列表
                for (int j = 0; j < coors.size() - 1; j += 2) {
                    Map<String, BigDecimal> coord = new HashMap<>();
                    coord.put("latitude", coors.get(j));
                    coord.put("longitude", coors.get(j + 1));
                    allCoordinates.add(coord);
                }

                // 限流：延迟 200 毫秒
                Thread.sleep(200);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Thread interrupted during rate limiting", e);
            }
        }
        post.setDistance(totalDistance);
        post.setPolyline(JSON.toJSONString(allCoordinates));
        Long userId = ThreadLocalUtil.get("userId");
        post.setUserId(userId);
        save(post);
    }

    /**
     * 游玩帖子
     *
     * @param postId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Post playPost(Long postId) {
        // 1. 查询帖子是否存在
        Post post = this.getById(postId);
        if (post == null) {
            throw new BusinessException(500, "帖子不存在");
        }

        // 2. 增加游玩次数
        post.setPlayCount(post.getPlayCount() + 1);

        // 3. 使用 MyBatis-Plus 更新帖子
        boolean updated = this.updateById(post);
        if (!updated) {
            throw new BusinessException(500, "更新游玩次数失败");
        }

        // 4. 返回更新后的帖子数据
        return post;
    }

    /**
     * 获取帖子列表
     *
     * @return
     */
    @Override
    public List<PostListVO> listPosts(String token, PostUserPageDTO postUserPageDTO) {
        List<PostListVO> allPostListVOS = new ArrayList<>();
        List<PostListVO> postListVOS = new ArrayList<>();
        Long userId = new Long(0);
        if (!StringUtils.isEmpty(token)) {
            userId = (Long) redisTemplate.opsForValue().get(token);
        }
        // 1. 执行分页查询
        Page<Post> page = new Page<>(postUserPageDTO.getPageNo(), postUserPageDTO.getPageSize());
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        // 2. 设置排序条件，按创建时间降序排序
        queryWrapper.orderByDesc(Post::getCreatedTime);
        if (!ObjectUtils.isEmpty(postUserPageDTO.getSearchCoordinates())) {
            Coordinate searchCoordinates = postUserPageDTO.getSearchCoordinates();

            BigDecimal latitude = searchCoordinates.getLatitude();
            BigDecimal longitude = searchCoordinates.getLongitude();

            // 添加 SQL 查询条件，使用 JSON_CONTAINS
            queryWrapper.apply(
                    "JSON_CONTAINS(route, JSON_OBJECT('latitude', {0}, 'longitude', {1}))",
                    latitude, longitude
            );
        }
        Page<Post> postPage = this.page(page, queryWrapper);

        // 3. 填充帖子列表
        for (Post record : postPage.getRecords()) {
            PostListVO postListVO = new PostListVO();
            BeanUtils.copyProperties(record, postListVO);
            String imageListStr = record.getImageList();  // 获取图片列表字符串
            if (imageListStr != null && !imageListStr.isEmpty()) {
                // 使用 Fastjson 解析 JSON 字符串为 List<String>
                List<String> imageList = JSON.parseArray(imageListStr, String.class);
                postListVO.setImageList(imageList);  // 设置到 PostHomeVO 中
            }
            Boolean collect = collectService.isCollect(userId, record.getId());
            Boolean isFollow = followService.isFollow(userId, record.getUserId());
            Boolean love = loveService.isLove(userId, record.getId());
            postListVO.setIsFollow(isFollow);
            postListVO.setIsCollect(collect);
            postListVO.setIsLove(love);
            JSONArray jsonArray = JSON.parseArray(postListVO.getRoute());
            // 第一个 name
            JSONObject firstItem = jsonArray.getJSONObject(0);
            String firstName = firstItem.getString("name");

            // 最后一个 name
            JSONObject lastItem = jsonArray.getJSONObject(jsonArray.size() - 1);
            String lastName = lastItem.getString("name");
            postListVO.setStartRoute(firstName);
            postListVO.setEndRoute(lastName);
            User user = userMapper.selectById(record.getUserId());
            postListVO.setAvatar(user.getAvatar());
            postListVO.setNickname(user.getNickname());
            allPostListVOS.add(postListVO);
        }

        // 4. 根据条件过滤帖子
        String criteria = postUserPageDTO.getCriteria();
        if ("附近".equals(criteria)) {
            // 获取用户的坐标
            BigDecimal userLatitude = postUserPageDTO.getOwnCoordinates().getLatitude();
            BigDecimal userLongitude = postUserPageDTO.getOwnCoordinates().getLongitude();

            for (PostListVO postListVO : allPostListVOS) {
                JSONArray jsonArray = JSON.parseArray(postListVO.getRoute());
                // 遍历 JSONArray，检查是否有符合条件的坐标
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    BigDecimal latitude = jsonObject.getBigDecimal("latitude");
                    BigDecimal longitude = jsonObject.getBigDecimal("longitude");

                    // 计算距离
                    double distance = calculateDistance(userLatitude.doubleValue(), userLongitude.doubleValue(),
                            latitude.doubleValue(), longitude.doubleValue());

                    // 判断距离是否在一公里内
                    if (distance <= 1.0) { // 1.0 表示一公里
                        postListVOS.add(postListVO);
                        break; // 找到符合条件的坐标，提前退出循环
                    }
                }
            }
        } else if ("推荐".equals(criteria)) {
            postListVOS = allPostListVOS; // 推荐条件，直接赋值
        } else if ("最新".equals(criteria)) {
            // 根据需求可以进行其他处理，这里可以添加最新逻辑
            postListVOS = allPostListVOS; // 假设最新也返回所有帖子
        }

        return postListVOS;
    }


    /**
     * 帖子详情
     *
     * @param postId
     * @return
     */
    @Override
    public PostVO getPostById(String token, Long postId) {
        Long userId = new Long(0);
        if (!StringUtils.isEmpty(token)) {
            userId = (Long) redisTemplate.opsForValue().get(token);
        }
        PostVO postVO = new PostVO();
        // 1. 查询帖子详情
        Post post = this.getById(postId);
        if (post == null) {
            throw new BusinessException(500, "帖子不存在");
        }
        BeanUtils.copyProperties(post, postVO);
        List<CoordinateDTO> coordinates = JSON.parseObject(post.getPolyline(), new TypeReference<List<CoordinateDTO>>() {
        });
        postVO.setPolyline(coordinates);
        String imageListStr = post.getImageList();  // 获取图片列表字符串
        if (imageListStr != null && !imageListStr.isEmpty()) {
            // 使用 Fastjson 解析 JSON 字符串为 List<String>
            List<String> imageList = JSON.parseArray(imageListStr, String.class);
            postVO.setImageList(imageList);  // 设置到 PostHomeVO 中
        }
        JSONArray jsonArray = JSON.parseArray(post.getRoute());
        // 第一个 name
        JSONObject firstItem = jsonArray.getJSONObject(0);
        String firstName = firstItem.getString("name");

        // 最后一个 name
        JSONObject lastItem = jsonArray.getJSONObject(jsonArray.size() - 1);
        String lastName = lastItem.getString("name");
        postVO.setStartRoute(firstName);
        postVO.setEndRoute(lastName);
        postVO.setCreatedTime(post.getCreatedTime().format(DateTimeFormatter.ofPattern("YYYY-MM-dd")));
        List<Coordinate> coordinateList = new ArrayList<>();
        // 遍历 JSONArray，检查是否有符合条件的坐标
        for (int i = 0; i < jsonArray.size(); i++) {
            Coordinate coordinate = new Coordinate();
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            BigDecimal latitude = jsonObject.getBigDecimal("latitude");
            BigDecimal longitude = jsonObject.getBigDecimal("longitude");
            String name = jsonObject.getString("name");
            coordinate.setLatitude(latitude);
            coordinate.setLongitude(longitude);
            coordinate.setName(name);
            coordinateList.add(coordinate);
        }
        postVO.setRoute(coordinateList);

        Coordinate addresCoordinate = JSON.parseObject(post.getAddress(), Coordinate.class);
        postVO.setAddress(addresCoordinate);
        List<CommentsVO> commentListByPostId = commentService.getCommentListByPostId(token, new CommentPostIdPageDTO(postId)).getList();
        User user = userMapper.selectById(post.getUserId());
        postVO.setAvatar(user.getAvatar());
        postVO.setNickname(user.getNickname());
        postVO.setCommentsVO(commentListByPostId);
        Boolean collect = collectService.isCollect(userId, postId);
        Boolean isFollow = followService.isFollow(userId, postVO.getUserId());
        Boolean love = loveService.isLove(userId, postId);
        postVO.setIsCollect(collect);
        postVO.setIsFollow(isFollow);
        postVO.setIsLove(love);
        return postVO;
    }

    /**
     * 获取发布帖子数量
     *
     * @param userId
     * @return
     */
    @Override
    public Long getPostCount(Long userId) {
        LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Post::getUserId, userId);
        Long aLong = baseMapper.selectCount(wrapper);
        return aLong;
    }

    @Override
    public PageVO<PostPageVO> queryPostPage(PostPageDTO postPageDTO) {
        Page<PostPageVO> page = new Page<>(postPageDTO.getPageNo(), postPageDTO.getPageSize());
        IPage<PostPageVO> postPage = baseMapper.queryPostPage(page, postPageDTO);
        PageVO<PostPageVO> pageVO = new PageVO<>();
        pageVO.setList(postPage.getRecords());
        pageVO.setTotal(postPage.getTotal());
        pageVO.setPages(postPage.getPages());
        return pageVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePost(List<Long> ids) {
        removeByIds(ids);
        loveService.remove(new LambdaQueryWrapper<>(Love.class).in(Love::getPostId, ids));
        collectService.remove(new LambdaQueryWrapper<>(Collect.class).in(Collect::getPostId, ids));
        commentService.remove(new LambdaQueryWrapper<>(Comment.class).in(Comment::getPostId, ids));
    }

    @Override
    public PageVO<PostHomeVO> getMyPost(Long userId, int pageNum, int pageSize, int type) {
        Page<Post> page = new Page<>(pageNum, pageSize);
        Page<Post> postPage = new Page<>();
        if (type == 0) {
            postPage = this.page(page, new LambdaQueryWrapper<Post>().eq(Post::getUserId, userId));
        } else if (type == 1) {
            postPage = this.page(page, new LambdaQueryWrapper<Post>()
                    .inSql(Post::getId, "SELECT post_id FROM collect WHERE user_id = " + userId));
        } else if (type == 2) {
            postPage = this.page(page, new LambdaQueryWrapper<Post>()
                    .inSql(Post::getId, "SELECT post_id FROM love WHERE user_id = " + userId));
        }
        PageVO<PostHomeVO> pageVO = new PageVO<>();
        List<PostHomeVO> postPageVOList = new ArrayList<>();
        for (Post record : postPage.getRecords()) {
            PostHomeVO postHomeVO = new PostHomeVO();
            BeanUtils.copyProperties(record, postHomeVO);
            String imageListStr = record.getImageList();  // 获取图片列表字符串
            if (imageListStr != null && !imageListStr.isEmpty()) {
                // 使用 Fastjson 解析 JSON 字符串为 List<String>
                List<String> imageList = JSON.parseArray(imageListStr, String.class);
                postHomeVO.setImageList(imageList);  // 设置到 PostHomeVO 中
            }
            JSONArray jsonArray = JSON.parseArray(record.getRoute());
            // 获取第一个和最后一个元素的 name
            if (jsonArray != null && !jsonArray.isEmpty()) {
                // 第一个 name
                JSONObject firstItem = jsonArray.getJSONObject(0);
                String firstName = firstItem.getString("name");

                // 最后一个 name
                JSONObject lastItem = jsonArray.getJSONObject(jsonArray.size() - 1);
                String lastName = lastItem.getString("name");
                postHomeVO.setStartRoute(firstName);
                postHomeVO.setDistance(record.getDistance());
                postHomeVO.setEndRoute(lastName);
            }
            postPageVOList.add(postHomeVO);
        }
        pageVO.setTotal(postPage.getTotal());
        pageVO.setList(postPageVOList);
        pageVO.setPages(postPage.getPages());
        return pageVO;
    }

    @Override
    public PageVO<PostListVO> listOtherPosts(PostOtherPageDTO postOtherPageDTO) {
        return null;
    }

    @Override
    public int getTotalPostCount() {
        return 0;
    }

    @Override
    public int getTodayNewPostCount() {
        return 0;
    }

    @Override
    public List<HashMap<String, Object>> getPostTrend() {
        return baseMapper.getPostTrend();
    }


    // 计算两点之间的距离，使用 Haversine 公式
    private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371; // 地球半径 (单位：公里)

        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);
        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        double distance = R * c; // 转换为公里

        return distance;
    }

}
